package com.cenntro.oss.interceptor;

import java.io.OutputStream;
import java.security.MessageDigest;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cenntro.auth.model.dbo.SysSooidDO;
import com.cenntro.common.redis.IRedisService;
import com.cenntro.common.util.KeyUtil;
import com.cenntro.common.util.KeyUtil.keyEnum;
import com.cenntro.common.util.MessageUtil;
import com.cenntro.common.util.result.Result;
import com.google.common.base.Joiner;

//@WebServlet
public class MyInterceptor implements HandlerInterceptor {

    private Logger LOG = LoggerFactory.getLogger(MyInterceptor.class);

    @Resource
    private IRedisService redisService;
    // @Resource
    // private CustomerService customerService;
    //
    // @Resource
    // private SystemLog systemLog;

    @CrossOrigin
    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object arg2) throws Exception {
        try {
            res.setHeader("Content-type", "application/json;charset=UTF-8");
            res.addHeader("Access-Control-Allow-Origin", "*");
            res.addHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE,HEAD");
            res.addHeader("Access-Control-Allow-Headers", "S_ID,content-type");
            res.addHeader("Access-Control-Max-Age", "3600000");
            res.addHeader("Access-Control-Allow-Credentials", "true");
            // 让请求，不被缓存，
            res.setHeader("Cache-Control", "no-cache");
            res.setHeader("Cache-Control", "no-store");
            res.setHeader("Pragma", "no-cache");
            res.setDateHeader("Expires", 0);
            
//            res.setHeader("Access-Control-Allow-Methods", "*");
//            res.setHeader("Access-Control-Allow-Headers", "*");
            if (req.getMethod().equals("OPTIONS")) {
                res.setStatus(HttpServletResponse.SC_OK);
                return false;
            }           
            
            LOG.info(req.getRequestURI());
            String requestMethord = req.getRequestURI();// 请求方法
            if (requestMethord == null) {
                return false;
            }
            // 获取请求参数
            JSONObject parameterMap = JSON
                    .parseObject(new BodyReaderHttpServletRequestWrapper(req).getBodyString(req));
            if (parameterMap != null && LOG.isInfoEnabled()) {
                LOG.info("preHandle : {}", parameterMap.toJSONString());
            }
            if (parameterMap != null) {
                String token = parameterMap.getString("token");
                LOG.info("token= {}", token);
                if (!StringUtils.isBlank(token)) {
                    String key = token.split("_")[0];
                    key = KeyUtil.keyOf(keyEnum.USER_OSS, key);
                    String sooStr = redisService.hget(key, token);
                    SysSooidDO soo = JSONObject.parseObject(sooStr, SysSooidDO.class);
                    if (soo != null) {
                        Map<String, String> map = redisService.hmget(key);
                        redisService.hmset(key, map);
                        redisService.expire(key, 15 * 24 * 60 * 60l);
                        return true;
                    } else {
                        OutputStream out = res.getOutputStream();
                        Result result = Result.error(MessageUtil.NEED_TO_LOGIN, "请求失败，需要重新登录");
                        out.write(JSON.toJSONString(result).getBytes());
                        return false;
                    }
                }
            }
        
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
    }

    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
        // TODO Auto-generated method stub
    }

    /**
     * 判断是否必传参数未填
     * @param signParam
     * @param timespan
     * @param mobileId
     * @param out
     * @return
     * @throws Exception
     */
    private boolean isParamErr(String signParam, String timespan, String mobileId, OutputStream out) throws Exception {
        if (StringUtils.isBlank(signParam) || StringUtils.isBlank(timespan) || StringUtils.isBlank(mobileId)) {
            try {
                LOG.info("参数错误 signParam= {}, timespan={}, mobileId ={}", signParam, timespan, mobileId);
                Result result = Result.error(MessageUtil.PARAM_ILLEGAL, MessageUtil.getMsg("PARAM.ILLEGAL"));
                out.write(JSON.toJSONString(result).getBytes());
                return Boolean.FALSE;
            } finally {
                if (out != null) {
                    try {
                        out.close();
                    } catch (Exception e) {
                        LOG.info("", e);
                    }
                }
            }
        }
        return Boolean.TRUE;
    }

    /**
     * 判断是否填签名错误
     * @param signParam
     * @param timespan
     * @param mobileId
     * @param out
     * @return
     * @throws Exception
     */
    private boolean isSignErr(Map<String, Object> paramMap, String signParam, OutputStream out) throws Exception {
        paramMap.remove("sign");
        paramMap.remove("debug");
        String join = Joiner.on("").join(paramMap.values());
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        md5.reset();
        md5.update(join.getBytes("UTF-8"));
        byte[] str = md5.digest();
        byte[] base64 = Base64Utils.encode(str);
        String sign = new String(base64); // .replaceAll("\\+", " "); // 签名
        if (!sign.equals(signParam)) {
            try {
                Result result = Result.error(MessageUtil.PARAM_ILLEGAL, MessageUtil.getMsg("PARAM.ILLEGAL"));
                out.write(JSON.toJSONString(result).getBytes());
                LOG.info("签名错误 signParam={}, sign={}, param={}", signParam, sign, join);
                return Boolean.FALSE;
            } finally {
                if (out != null) {
                    try {
                        out.close();
                    } catch (Exception e) {
                        LOG.info("", e);
                    }
                }
            }
        }
        return Boolean.TRUE;
    }
    // /**
    // * 判断是否填签名错误
    // * @param signParam
    // * @param timespan
    // * @param mobileId
    // * @param out
    // * @return
    // * @throws Exception
    // */
    // private Boolean neetToLogin(String token, OutputStream out, Object arg2)
    // throws Exception {
    // // 需要登录
    // HandlerMethod hm = (HandlerMethod) arg2;
    // NeedToLogin[] nTL=
    // hm.getBean().getClass().getDeclaredAnnotationsByType(NeedToLogin.class);
    // NeedToLogin needToLogin = hm.getMethodAnnotation(NeedToLogin.class);
    // if (needToLogin != null || ArrayUtils.isNotEmpty(nTL)) {
    // if (!StringUtils.isBlank(token)){
    // CustomerDO customerDO = customerService.getCustomerByToken(token);
    // if(customerDO != null){
    // return true;
    // }
    // }
    // try {
    // Result result = Result.error(MessageUtil.PARAM_ILLEGAL,
    // MessageUtil.getMsg("need_to_login"));
    // out.write(JSON.toJSONString(result).getBytes());
    // LOG.info("未登录不能访问 token= {}", token);
    // return Boolean.FALSE;
    // } finally {
    // if (out != null) {
    // try {
    // out.close();
    // } catch (Exception e) {
    // LOG.info("", e);
    // }
    // }
    // }
    // }
    // return Boolean.TRUE;
    // }

    // private SystemLogDO getSystemLog(HttpServletRequest req, Map<String,
    // Object> paramMap, Object arg2){
    // try{
    // SystemLogDO systemLog = new SystemLogDO();
    // String str = "";
    // for(String key : paramMap.keySet()){
    // if (str.length() > 0){
    // str += "&";
    // }
    // str += key + "=" + paramMap.get(key);
    // }
    // systemLog.setParam(str);
    // systemLog.setType(1);
    // systemLog.setUri(req.getRequestURL().toString());
    // systemLog.setIp(getIpAddr(req));
    // BeanUtils.populate(systemLog, paramMap);
    // HandlerMethod hm = (HandlerMethod) arg2;
    // systemLog.setClazz(hm.getBean().getClass().getName());
    // systemLog.setReqMethod(hm.getMethod().getName());
    // return systemLog;
    // }catch(Exception ex){
    // LOG.warn("transform err");
    // }
    // return null;
    // }
    /** 
    * 获取用户真实IP地址，不使用request.getRemoteAddr()的原因是有可能用户使用了代理软件方式避免真实IP地址, 
    * 可是，如果通过了多级反向代理的话，X-Forwarded-For的值并不止一个，而是一串IP值 
    *  
    * @return ip
    */
    private String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值，第一个ip才是真实ip
            if (ip.indexOf(",") != -1) {
                ip = ip.split(",")[0];
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
